using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using ProjectNoClue.Graphics;

using FarseerGames.FarseerPhysics;

namespace ProjectNoClue
{
	//TODO: Replace With real statemanager class
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		GraphicsDeviceManager graphics;
		LineBatch draw;

		SpriteBatch sb;
		SpriteFont font;

		Part test;
		Part test2;

		int frameRate = 0;
		int frameCounter = 0;
		TimeSpan elapsedTime = TimeSpan.Zero;

		ResolveTexture2D blurTes;

		PhysicsSimulator physics = new PhysicsSimulator();

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";

			//this.IsFixedTimeStep = false;
			//graphics.SynchronizeWithVerticalRetrace = false;
			Window.AllowUserResizing = true;

			IsMouseVisible = true;

		}

		protected override void Initialize()
		{
			physics.MaxContactsToDetect = 20;
			physics.MaxContactsToResolve = 10;
			physics.Iterations = 10;

			base.Initialize();
		}

		Part basep;

		protected override void LoadContent()
		{
			draw = new LineBatch(this);
			sb = new SpriteBatch(GraphicsDevice);
			font = Content.Load<SpriteFont>(@"font");
			test = Content.Load<Part>("test");
			basep = Content.Load<Part>("base");

			test2 = (Part)test.Clone();

			//test.Rotation = MathHelper.PiOver2 + MathHelper.Pi;
			//test.Rotation = MathHelper.PiOver2;

			test.Body.LinearDragCoefficient = 3f;
			test.Body.RotationalDragCoefficient = 8000f;
			test.Body.MomentOfInertia /= 5;
			//test.Body.MomentOfInertia = float.PositiveInfinity;
			AddToPhysics(test);
			AddToPhysics(basep);

			basep.Body.IsStatic = true;

			Resise(null, null);
		}

		void AddToPhysics(Part part)
		{
			physics.Add(part.Body);
			Part.Shape[] shapes = part.Shapes;
			for (int ii = 0; ii < shapes.Length; ++ii)
			{
				physics.Add(shapes[ii].Geom);
			}
		}

		void Resise(object sender, EventArgs e)
		{
			PresentationParameters pp = GraphicsDevice.PresentationParameters;
			if (blurTes != null)
				blurTes.Dispose();

			blurTes = new ResolveTexture2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, pp.BackBufferFormat);
		}


		protected override void UnloadContent()
		{
		}

		string fpsString = "";

		protected override void Update(GameTime gameTime)
		{
			if (Input.OpenMap()) //this was just a test for static stuff, ignore it.
			{
				this.Exit();
			}

			Input.Update();

			//test.Rotation = (float)gameTime.TotalGameTime.TotalSeconds * 2;

			Vector2 stick = Input.Move();
			float mag = stick.Length();

			if (mag > .01)
			{
				float angle = (float)Math.Atan2(stick.Y, stick.X);

				float rot = test.Rotation + MathHelper.PiOver2 + MathHelper.Pi;

				angle = ClampAngle(angle, rot, MathHelper.Pi);

				stick.X = (float)Math.Cos(angle) * mag * 1000;
				stick.Y = (float)Math.Sin(angle) * mag * 1000;

				test2.Rotation = angle + MathHelper.PiOver2;

				test.Body.ApplyForceAtLocalPoint(stick, new Vector2(0, -50));

			}
			elapsedTime += gameTime.ElapsedGameTime;

			if (elapsedTime > TimeSpan.FromSeconds(1))
			{
				elapsedTime -= TimeSpan.FromSeconds(1);
				frameRate = frameCounter;
				fpsString = frameRate.ToString();
				frameCounter = 0;
			}

			physics.Update((float)gameTime.ElapsedGameTime.TotalSeconds);

			base.Update(gameTime);
		}

		float ClampAngle(float toclamp, float offset, float field)
		{
			float hfield = field / 2f;
			float split = offset + MathHelper.Pi;

			//getting both angles in the same 360 pie
			while (toclamp <= -MathHelper.Pi) toclamp += MathHelper.TwoPi;
			while (toclamp > MathHelper.Pi) toclamp -= MathHelper.TwoPi;

			while (offset <= -MathHelper.Pi) offset += MathHelper.TwoPi;
			while (offset > MathHelper.Pi) offset -= MathHelper.TwoPi;

			while (split <= -MathHelper.Pi) split += MathHelper.TwoPi;
			while (split > MathHelper.Pi) split -= MathHelper.TwoPi;


			if (toclamp < split && offset > 0)
				toclamp += MathHelper.TwoPi;
			else if (toclamp > split && offset < 0)
				toclamp -= MathHelper.TwoPi;

			/*if (toclamp > split && toclamp <= MathHelper.Pi)
				toclamp -= MathHelper.TwoPi;*/
			/*else if (toclamp < split && toclamp >= MathHelper.Pi)
				toclamp -= MathHelper.TwoPi;*/



			if (toclamp < offset - hfield)
				toclamp = offset - hfield;
			else if (toclamp > offset + hfield)
				toclamp = offset + hfield;

			return toclamp;

		}

		protected override void Draw(GameTime gameTime)
		{
			graphics.GraphicsDevice.Clear(Color.Black);

			draw.Begin();

			draw.Draw(test);
			draw.Draw(basep);
			draw.Draw(test2);

			draw.End();

			/*const byte blurAmount = 200;    // higher = more blur

			sb.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
			sb.Draw(blurTes, Vector2.Zero, new Color(255, 255, 255, blurAmount));
			sb.End();
			so,
			GraphicsDevice.ResolveBackBuffer(blurTes);

			sb.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
			sb.Draw(blurTes, Vector2.Zero, Color.White);
			sb.End();*/

			frameCounter++;
			sb.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
			sb.DrawString(font, fpsString, Vector2.Zero, Color.White);
			sb.End();

			base.Draw(gameTime);
		}
	}
}
